home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 October / Enter 10 2006.iso / Uzytki / Spiceworks Desktop 0.8.34 Beta / Spiceworks.exe / ruby / bin / gem_server < prev    next >
Encoding:
Text File  |  2006-05-26  |  10.5 KB  |  441 lines

  1. #!/usr/bin/env ruby
  2.  
  3. DOC_TEMPLATE = <<-WEBPAGE
  4. <?xml version="1.0" encoding="iso-8859-1"?>
  5. <!DOCTYPE html 
  6.      PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  7.      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  8.  
  9. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  10. <head>
  11.   <title>RubyGems Documentation Index</title>
  12.   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  13.   <link rel="stylesheet" href="rdoc-style.css" type="text/css" media="screen" />
  14. </head>
  15. <body>
  16.   <div id="fileHeader">
  17.     <h1>RubyGems Documentation Index</h1>
  18.   </div>
  19.   <!-- banner header -->
  20.  
  21. <div id="bodyContent">
  22.   <div id="contextContent">
  23.     <div id="description">
  24.       <h1>Summary</h1>
  25. <p>There are %gem_count% gems installed:</p>
  26. <p>
  27. START:specs
  28. IFNOT:is_last
  29. <a href="#%name%">%name%</a>,
  30. ENDIF:is_last
  31. IF:is_last
  32. <a href="#%name%">%name%</a>.
  33. ENDIF:is_last
  34. END:specs
  35. <h1>Gems</h1>
  36.  
  37. <dl>
  38. START:specs
  39. <dt>
  40. IF:first_name_entry
  41.   <a name="%name%"></a>
  42. ENDIF:first_name_entry
  43. <b>%name% %version%</b>
  44. IF:rdoc_installed
  45.   <a href="%doc_path%">[rdoc]</a>
  46. ENDIF:rdoc_installed
  47. IFNOT:rdoc_installed
  48.   <span title="rdoc not installed">[rdoc]</span>
  49. ENDIF:rdoc_installed
  50. IF:homepage
  51. <a href="%homepage%" target="_blank" title="%homepage%">[www]</a>
  52. ENDIF:homepage
  53. IFNOT:homepage
  54. <span title="no homepage available">[www]</span>
  55. ENDIF:homepage
  56. IF:has_deps
  57.  - depends on 
  58. START:dependencies
  59. IFNOT:is_last
  60. <a href="#%name%" title="%version%">%name%</a>,
  61. ENDIF:is_last
  62. IF:is_last
  63. <a href="#%name%" title="%version%">%name%</a>.
  64. ENDIF:is_last
  65. END:dependencies
  66. ENDIF:has_deps
  67. </dt>
  68. <dd>
  69. %summary%
  70. IF:executables
  71.   <br/>
  72.  
  73. IF:only_one_executable
  74.     Executable is
  75. ENDIF:only_one_executable
  76.   
  77. IFNOT:only_one_executable
  78.     Executables are
  79. ENDIF:only_one_executable
  80.  
  81. START:executables
  82. IFNOT:is_last
  83.       <span class="context-item-name">%executable%</span>,
  84. ENDIF:is_last
  85. IF:is_last
  86.       <span class="context-item-name">%executable%</span>.
  87. ENDIF:is_last
  88. END:executables
  89. ENDIF:executables
  90. <br/>
  91. <br/>
  92. </dd>
  93. END:specs
  94. </dl>
  95.  
  96.     </div>
  97.    </div>
  98.   </div>
  99. <div id="validator-badges">
  100.   <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
  101. </div>
  102. </body>
  103. </html>
  104. WEBPAGE
  105.  
  106.  
  107. # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
  108. RDOC_CSS = <<-RDOCCSS
  109. body {
  110.     font-family: Verdana,Arial,Helvetica,sans-serif;
  111.     font-size:   90%;
  112.     margin: 0;
  113.     margin-left: 40px;
  114.     padding: 0;
  115.     background: white;
  116. }
  117.  
  118. h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
  119. h1 { font-size: 150%; }
  120. h2,h3,h4 { margin-top: 1em; }
  121.  
  122. a { background: #eef; color: #039; text-decoration: none; }
  123. a:hover { background: #039; color: #eef; }
  124.  
  125. /* Override the base stylesheet's Anchor inside a table cell */
  126. td > a {
  127.   background: transparent;
  128.   color: #039;
  129.   text-decoration: none;
  130. }
  131.  
  132. /* and inside a section title */
  133. .section-title > a {
  134.   background: transparent;
  135.   color: #eee;
  136.   text-decoration: none;
  137. }
  138.  
  139. /* === Structural elements =================================== */
  140.  
  141. div#index {
  142.     margin: 0;
  143.     margin-left: -40px;
  144.     padding: 0;
  145.     font-size: 90%;
  146. }
  147.  
  148.  
  149. div#index a {
  150.     margin-left: 0.7em;
  151. }
  152.  
  153. div#index .section-bar {
  154.    margin-left: 0px;
  155.    padding-left: 0.7em;
  156.    background: #ccc;
  157.    font-size: small;
  158. }
  159.  
  160.  
  161. div#classHeader, div#fileHeader {
  162.     width: auto;
  163.     color: white;
  164.     padding: 0.5em 1.5em 0.5em 1.5em;
  165.     margin: 0;
  166.     margin-left: -40px;
  167.     border-bottom: 3px solid #006;
  168. }
  169.  
  170. div#classHeader a, div#fileHeader a {
  171.     background: inherit;
  172.     color: white;
  173. }
  174.  
  175. div#classHeader td, div#fileHeader td {
  176.     background: inherit;
  177.     color: white;
  178. }
  179.  
  180.  
  181. div#fileHeader {
  182.     background: #057;
  183. }
  184.  
  185. div#classHeader {
  186.     background: #048;
  187. }
  188.  
  189.  
  190. .class-name-in-header {
  191.   font-size:  180%;
  192.   font-weight: bold;
  193. }
  194.  
  195.  
  196. div#bodyContent {
  197.     padding: 0 1.5em 0 1.5em;
  198. }
  199.  
  200. div#description {
  201.     padding: 0.5em 1.5em;
  202.     background: #efefef;
  203.     border: 1px dotted #999;
  204. }
  205.  
  206. div#description h1,h2,h3,h4,h5,h6 {
  207.     color: #125;;
  208.     background: transparent;
  209. }
  210.  
  211. div#validator-badges {
  212.     text-align: center;
  213. }
  214. div#validator-badges img { border: 0; }
  215.  
  216. div#copyright {
  217.     color: #333;
  218.     background: #efefef;
  219.     font: 0.75em sans-serif;
  220.     margin-top: 5em;
  221.     margin-bottom: 0;
  222.     padding: 0.5em 2em;
  223. }
  224.  
  225.  
  226. /* === Classes =================================== */
  227.  
  228. table.header-table {
  229.     color: white;
  230.     font-size: small;
  231. }
  232.  
  233. .type-note {
  234.     font-size: small;
  235.     color: #DEDEDE;
  236. }
  237.  
  238. .xxsection-bar {
  239.     background: #eee;
  240.     color: #333;
  241.     padding: 3px;
  242. }
  243.  
  244. .section-bar {
  245.    color: #333;
  246.    border-bottom: 1px solid #999;
  247.     margin-left: -20px;
  248. }
  249.  
  250.  
  251. .section-title {
  252.     background: #79a;
  253.     color: #eee;
  254.     padding: 3px;
  255.     margin-top: 2em;
  256.     margin-left: -30px;
  257.     border: 1px solid #999;
  258. }
  259.  
  260. .top-aligned-row {  vertical-align: top }
  261. .bottom-aligned-row { vertical-align: bottom }
  262.  
  263. /* --- Context section classes ----------------------- */
  264.  
  265. .context-row { }
  266. .context-item-name { font-family: monospace; font-weight: bold; color: black; }
  267. .context-item-value { font-size: small; color: #448; }
  268. .context-item-desc { color: #333; padding-left: 2em; }
  269.  
  270. /* --- Method classes -------------------------- */
  271. .method-detail {
  272.     background: #efefef;
  273.     padding: 0;
  274.     margin-top: 0.5em;
  275.     margin-bottom: 1em;
  276.     border: 1px dotted #ccc;
  277. }
  278. .method-heading {
  279.   color: black;
  280.   background: #ccc;
  281.   border-bottom: 1px solid #666;
  282.   padding: 0.2em 0.5em 0 0.5em;
  283. }
  284. .method-signature { color: black; background: inherit; }
  285. .method-name { font-weight: bold; }
  286. .method-args { font-style: italic; }
  287. .method-description { padding: 0 0.5em 0 0.5em; }
  288.  
  289. /* --- Source code sections -------------------- */
  290.  
  291. a.source-toggle { font-size: 90%; }
  292. div.method-source-code {
  293.     background: #262626;
  294.     color: #ffdead;
  295.     margin: 1em;
  296.     padding: 0.5em;
  297.     border: 1px dashed #999;
  298.     overflow: hidden;
  299. }
  300.  
  301. div.method-source-code pre { color: #ffdead; overflow: hidden; }
  302.  
  303. /* --- Ruby keyword styles --------------------- */
  304.  
  305. .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
  306.  
  307. .ruby-constant  { color: #7fffd4; background: transparent; }
  308. .ruby-keyword { color: #00ffff; background: transparent; }
  309. .ruby-ivar    { color: #eedd82; background: transparent; }
  310. .ruby-operator  { color: #00ffee; background: transparent; }
  311. .ruby-identifier { color: #ffdead; background: transparent; }
  312. .ruby-node    { color: #ffa07a; background: transparent; }
  313. .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
  314. .ruby-regexp  { color: #ffa07a; background: transparent; }
  315. .ruby-value   { color: #7fffd4; background: transparent; }
  316. RDOCCSS
  317.  
  318.  
  319.  
  320. ##
  321. # gem_server and gem_server.cgi are equivalent programs that allow  
  322. # users to serve gems for consumption by `gem --remote-install`.
  323. # gem_server starts an HTTP server on the given port, and serves the folowing:
  324. # * "/" - Browsing of gem spec files for installed gems
  325. # * "/yaml" - Full yaml dump of metadata for installed gems
  326. # * "/gems" - Direct access to download the installable gems
  327. #
  328. # Usage: gem_server [-p portnum] [-d gem_path]
  329. # port_num:: The TCP port the HTTP server will bind to
  330. # gem_path::
  331. #   Root gem directory containing both "cache" and "specifications"
  332. #   subdirectories.
  333. if __FILE__ == $0
  334.   require 'rubygems'
  335.   Gem.manage_gems
  336.   require 'webrick'
  337.   require 'yaml'
  338.   require 'optparse'
  339.   require 'rdoc/template'
  340.   Socket.do_not_reverse_lookup=true
  341.   options = {}
  342.   ARGV.options do |opts|
  343.     opts.on_tail("--help", 
  344.       "show this message") {puts opts; exit}
  345.     opts.on('-pPORT','--port=PORT', 
  346.       "Specify the port to listen on") { |options[:port]| }
  347.     opts.on('-dGEMDIR','--dir=GEMDIR', 
  348.       "Specify the directory from which to serve Gems") { |options[:gemdir]| }
  349.     opts.parse!
  350.   end
  351.  
  352.   s = WEBrick::HTTPServer.new(:Port => options[:port] || 8808)
  353.   s.mount_proc("/yaml") { |req, res|
  354.     fn = File.join(options[:gemdir] || Gem.dir, "specifications")
  355.     res['content-type'] = 'text/plain'
  356.     res['date'] = File.stat(fn).mtime
  357.     res.body << Gem::SourceIndex.from_installed_gems(fn).to_yaml
  358.   }
  359.  
  360.   s.mount_proc("/rdoc-style.css") { |req, res|
  361.     fn = File.join(options[:gemdir] || Gem.dir, "specifications")
  362.     res['content-type'] = 'text/css'
  363.     res['date'] = File.stat(fn).mtime
  364.     res.body << RDOC_CSS
  365.   }
  366.  
  367.   s.mount_proc("/") { |req, res|
  368.     specs = []
  369.     specifications_dir = File.join(options[:gemdir] || Gem.dir, "specifications")
  370.     total_file_count = 0
  371.     Gem::SourceIndex.from_installed_gems(specifications_dir).each do |path, spec|
  372.       total_file_count += spec.files.size
  373.       deps = spec.dependencies.collect { |dep|
  374.         {
  375.           "name" => dep.name, 
  376.           "version" => dep.version_requirements.to_s,
  377.         }
  378.       }
  379.       deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
  380.       deps.last["is_last"] = true unless deps.empty?
  381.       
  382.       # executables
  383.       executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
  384.       executables = nil if executables.empty?
  385.       executables.last["is_last"] = true if executables
  386.       
  387.       specs << {
  388.         "authors"        => spec.authors.sort.join(", "),
  389.         "date"           => spec.date.to_s,
  390.         "dependencies"   => deps,
  391.         "doc_path"       => ('/doc_root/' + spec.full_name + '/rdoc/index.html'),
  392.         "executables"    => executables,
  393.     "only_one_executable" => (executables && executables.size==1),
  394.         "full_name"      => spec.full_name,
  395.         "has_deps"       => !deps.empty?,
  396.         "homepage"       => spec.homepage,
  397.         "name"           => spec.name,
  398.         "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
  399.         "summary"        => spec.summary,
  400.         "version"        => spec.version.to_s,
  401.       }
  402.     end
  403.     specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
  404.     specs.last["is_last"] = true
  405.  
  406.     # tag all specs with first_name_entry 
  407.     last_spec = nil
  408.     specs.each do |spec|
  409.       is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
  410.       spec["first_name_entry"] = is_first
  411.       last_spec = spec
  412.     end
  413.     
  414.     # create page from template
  415.     template = TemplatePage.new(DOC_TEMPLATE)
  416.     res['content-type'] = 'text/html'
  417.     template.write_html_on(
  418.       res.body, 
  419.       {
  420.         "gem_count" => specs.size.to_s,
  421.         "specs" => specs,
  422.         "total_file_count" => total_file_count.to_s,
  423.       }
  424.     )
  425.     
  426.   }
  427.   {
  428.     "/gems" => "/cache/",
  429.     "/doc_root" => "/doc/",
  430.   }.each do |mount_point, mount_dir|
  431.     s.mount(
  432.       mount_point,
  433.       WEBrick::HTTPServlet::FileHandler,
  434.       File.join(options[:gemdir] || Gem.dir, mount_dir),
  435.       true)
  436.   end
  437.   trap("INT") { s.shutdown; exit! }
  438.   s.start
  439. end
  440.